/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <stdio.h>
#include "common/hc32f4a0_errno.h"
#include "core/include/hc32f4a0_regs_intc.h"
#include "core/include/hc32f4a0_intc.h"

/*******************************************************************************
 * Static
 ******************************************************************************/
static void            *__g_p_irq_handler_arg[IRQ_NUM_MAX] = {NULL};
static p_fn_irq_handler __g_pfn_irq_handler[IRQ_NUM_MAX]   = {NULL};

/*******************************************************************************
 * Code
 ******************************************************************************/
void NMI_Handler(void){
    while(1);
}

/**
 * \brief 硬件错误异常处理函数
 */
void HardFault_Handler(void){
    while(1);
}

/**
 * \brief 内存管理异常处理函数
 */
void MemManage_Handler(void){
    while(1);
}

/**
 * \brief 总线错误异常处理函数
 */
void BusFault_Handler(void){
    while(1);
}

void UsageFault_Handler(void){
    while(1);
}

__attribute__((weak)) void SVC_Handler(void){
    while(1);
}

__attribute__((weak)) void DebugMon_Handler(void){
    while(1);
}

__attribute__((weak)) void PendSV_Handler(void){
    while(1);
}

/**
 * \brief 中断号x处理函数
 */
void IRQ00x_Handler(void){
    int irq_num;
    /* 获取中断号*/
    irq_num = __NVIC_IRQ_NumGet();
    /* 调用中断回调*/
    if (__g_pfn_irq_handler[irq_num] != NULL) {
        __g_pfn_irq_handler[irq_num](__g_p_irq_handler_arg[irq_num]);
    }
}

/**
 * \brief 注销中断
 */
int intc_irq_resign(IRQn_Type irq_num){
    volatile uint32_t *p_intc_sel;
    int                ret = 0;

    if ((irq_num < Int000_IRQn) || (irq_num > Int143_IRQn)) {
        ret = -EINVAL;
    } else {
        p_intc_sel = (volatile uint32_t *)((uint32_t)(&HC32F4A0_INTC->SEL0) + (4 * (uint32_t)irq_num));
        WRITE_REG32(*p_intc_sel, 0x1FFu);
        __g_pfn_irq_handler[irq_num]   = NULL;
        __g_p_irq_handler_arg[irq_num] = NULL;
    }
    return ret;
}

/**
 * \brief 配置中断
 */
int intc_irq_sign_in(const struct hc32f4a0_irq_cfg *p_irq_sign_cfg){
    volatile uint32_t *p_intc_sel_x;
    int                ret = 0;

    if (NULL == p_irq_sign_cfg) {
        ret = -EINVAL;
    } else {
        /* IRQ032~127 whether out of range */
        if ((((((uint32_t)p_irq_sign_cfg->int_src / 0x20) * 6 + 0x20) > (uint32_t)p_irq_sign_cfg->IRQn) || \
             ((((uint32_t)p_irq_sign_cfg->int_src / 0x20) * 6 + 0x25) < (uint32_t)p_irq_sign_cfg->IRQn))&& \
             ((uint32_t)p_irq_sign_cfg->IRQn >= 0x20)) {
            ret = -EINVAL;
        } else {
            p_intc_sel_x = (volatile uint32_t *)((uint32_t)(&HC32F4A0_INTC->SEL0) + (4 * (uint32_t)p_irq_sign_cfg->IRQn));
            /* for MISRAC2004-12.4 */
            if (0x1FFUL == ((*p_intc_sel_x) & 0x1FFUL)) {
                WRITE_REG32(*p_intc_sel_x, p_irq_sign_cfg->int_src);
                __g_pfn_irq_handler[p_irq_sign_cfg->IRQn]   = p_irq_sign_cfg->p_fn_cb;
                __g_p_irq_handler_arg[p_irq_sign_cfg->IRQn] = p_irq_sign_cfg->p_arg;
            } else if ((uint32_t)(p_irq_sign_cfg->int_src) == ((*p_intc_sel_x) & 0x1FFUL)) {
                WRITE_REG32(*p_intc_sel_x, p_irq_sign_cfg->int_src);
                __g_pfn_irq_handler[p_irq_sign_cfg->IRQn]   = p_irq_sign_cfg->p_fn_cb;
                __g_p_irq_handler_arg[p_irq_sign_cfg->IRQn] = p_irq_sign_cfg->p_arg;
            } else {
                ret = -EPERM;
            }
        }
    }
    return ret;
}
